home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / lpd / printcap.c < prev    next >
C/C++ Source or Header  |  1990-02-16  |  9KB  |  432 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifndef lint
  14. static char sccsid[] = "@(#)printcap.c    5.2 (Berkeley) 5/5/88";
  15. #endif /* not lint */
  16.  
  17. #define MAXHOP    32    /* max number of tc= indirections */
  18.  
  19. #ifdef sprite
  20. #include "lp.h"
  21. #else
  22. #define    BUFSIZ    1024
  23. #include <ctype.h>
  24. #include <stdio.h>
  25. #endif
  26.  
  27. /*
  28.  * termcap - routines for dealing with the terminal capability data base
  29.  *
  30.  * BUG:        Should use a "last" pointer in tbuf, so that searching
  31.  *        for capabilities alphabetically would not be a n**2/2
  32.  *        process when large numbers of capabilities are given.
  33.  * Note:    If we add a last pointer now we will screw up the
  34.  *        tc capability. We really should compile termcap.
  35.  *
  36.  * Essentially all the work here is scanning and decoding escapes
  37.  * in string capabilities.  We don't use stdio because the editor
  38.  * doesn't, and because living w/o it is not hard.
  39.  */
  40.  
  41. #define PRINTCAP
  42.  
  43. #ifdef PRINTCAP
  44. #define tgetent    pgetent
  45. #define tskip    pskip
  46. #define tgetstr    pgetstr
  47. #define tdecode pdecode
  48. #define tgetnum    pgetnum
  49. #define    tgetflag pgetflag
  50. #define tdecode pdecode
  51. #define tnchktc    pnchktc
  52. #define    tnamatch pnamatch
  53. #undef E_TERMCAP
  54. #define E_TERMCAP "/etc/printcap"
  55. #define V6
  56. #endif
  57.  
  58. static    FILE *pfp = NULL;    /* printcap data base file pointer */
  59. static    char *tbuf;
  60. static    int hopcount;        /* detect infinite loops in termcap, init 0 */
  61. static  char *tskip();
  62. char    *tgetstr();
  63. static  char *tdecode();
  64. char    *getenv();
  65.  
  66. /*
  67.  * Similar to tgetent except it returns the next enrty instead of
  68.  * doing a lookup.
  69.  */
  70. getprent(bp)
  71.     register char *bp;
  72. {
  73.     register int c, skip = 0;
  74.  
  75.     if (pfp == NULL && (pfp = fopen(E_TERMCAP, "r")) == NULL)
  76.         return(-1);
  77.     tbuf = bp;
  78.     for (;;) {
  79.         switch (c = getc(pfp)) {
  80.         case EOF:
  81.             fclose(pfp);
  82.             pfp = NULL;
  83.             return(0);
  84.         case '\n':
  85.             if (bp == tbuf) {
  86.                 skip = 0;
  87.                 continue;
  88.             }
  89.             if (bp[-1] == '\\') {
  90.                 bp--;
  91.                 continue;
  92.             }
  93.             *bp = '\0';
  94.             return(1);
  95.         case '#':
  96.             if (bp == tbuf)
  97.                 skip++;
  98.         default:
  99.             if (skip)
  100.                 continue;
  101.             if (bp >= tbuf+BUFSIZ) {
  102.                 write(2, "Termcap entry too long\n", 23);
  103.                 *bp = '\0';
  104.                 return(1);
  105.             }
  106.             *bp++ = c;
  107.         }
  108.     }
  109. }
  110.  
  111. endprent()
  112. {
  113.     if (pfp != NULL)
  114.         fclose(pfp);
  115. }
  116.  
  117. /*
  118.  * Get an entry for terminal name in buffer bp,
  119.  * from the termcap file.  Parse is very rudimentary;
  120.  * we just notice escaped newlines.
  121.  */
  122. tgetent(bp, name)
  123.     char *bp, *name;
  124. {
  125.     register char *cp;
  126.     register int c;
  127.     register int i = 0, cnt = 0;
  128.     char ibuf[BUFSIZ];
  129.     char *cp2;
  130.     int tf;
  131.  
  132.     tbuf = bp;
  133.     tf = 0;
  134. #ifndef V6
  135.     cp = getenv("TERMCAP");
  136.     /*
  137.      * TERMCAP can have one of two things in it. It can be the
  138.      * name of a file to use instead of /etc/termcap. In this
  139.      * case it better start with a "/". Or it can be an entry to
  140.      * use so we don't have to read the file. In this case it
  141.      * has to already have the newlines crunched out.
  142.      */
  143.     if (cp && *cp) {
  144.         if (*cp!='/') {
  145.             cp2 = getenv("TERM");
  146.             if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
  147.                 strcpy(bp,cp);
  148.                 return(tnchktc());
  149.             } else {
  150.                 tf = open(E_TERMCAP, 0);
  151.             }
  152.         } else
  153.             tf = open(cp, 0);
  154.     }
  155.     if (tf==0)
  156.         tf = open(E_TERMCAP, 0);
  157. #else
  158.     tf = open(E_TERMCAP, 0);
  159. #endif
  160.     if (tf < 0)
  161.         return (-1);
  162.     for (;;) {
  163.         cp = bp;
  164.         for (;;) {
  165.             if (i == cnt) {
  166.                 cnt = read(tf, ibuf, BUFSIZ);
  167.                 if (cnt <= 0) {
  168.                     close(tf);
  169.                     return (0);
  170.                 }
  171.                 i = 0;
  172.             }
  173.             c = ibuf[i++];
  174.             if (c == '\n') {
  175.                 if (cp > bp && cp[-1] == '\\'){
  176.                     cp--;
  177.                     continue;
  178.                 }
  179.                 break;
  180.             }
  181.             if (cp >= bp+BUFSIZ) {
  182.                 write(2,"Termcap entry too long\n", 23);
  183.                 break;
  184.             } else
  185.                 *cp++ = c;
  186.         }
  187.         *cp = 0;
  188.  
  189.         /*
  190.          * The real work for the match.
  191.          */
  192.         if (tnamatch(name)) {
  193.             close(tf);
  194. #ifdef sprite
  195.             return 1;
  196. #else
  197.             return(tnchktc());
  198. #endif
  199.         }
  200.     }
  201. }
  202.  
  203. #ifndef sprite
  204. /*
  205.  * tnchktc: check the last entry, see if it's tc=xxx. If so,
  206.  * recursively find xxx and append that entry (minus the names)
  207.  * to take the place of the tc=xxx entry. This allows termcap
  208.  * entries to say "like an HP2621 but doesn't turn on the labels".
  209.  * Note that this works because of the left to right scan.
  210.  */
  211. tnchktc()
  212. {
  213.     register char *p, *q;
  214.     char tcname[16];    /* name of similar terminal */
  215.     char tcbuf[BUFSIZ];
  216.     char *holdtbuf = tbuf;
  217.     int l;
  218.  
  219.     p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  220.     while (*--p != ':')
  221.         if (p<tbuf) {
  222.             write(2, "Bad termcap entry\n", 18);
  223.             return (0);
  224.         }
  225.     p++;
  226.     /* p now points to beginning of last field */
  227.     if (p[0] != 't' || p[1] != 'c')
  228.         return(1);
  229.     strcpy(tcname,p+3);
  230.     q = tcname;
  231.     while (q && *q != ':')
  232.         q++;
  233.     *q = 0;
  234.     if (++hopcount > MAXHOP) {
  235.         write(2, "Infinite tc= loop\n", 18);
  236.         return (0);
  237.     }
  238.     if (tgetent(tcbuf, tcname) != 1)
  239.         return(0);
  240.     for (q=tcbuf; *q != ':'; q++)
  241.         ;
  242.     l = p - holdtbuf + strlen(q);
  243.     if (l > BUFSIZ) {
  244.         write(2, "Termcap entry too long\n", 23);
  245.         q[BUFSIZ - (p-tbuf)] = 0;
  246.     }
  247.     strcpy(p, q+1);
  248.     tbuf = holdtbuf;
  249.     return(1);
  250. }
  251. #endif
  252. /*
  253.  * Tnamatch deals with name matching.  The first field of the termcap
  254.  * entry is a sequence of names separated by |'s, so we compare
  255.  * against each such name.  The normal : terminator after the last
  256.  * name (before the first field) stops us.
  257.  */
  258. tnamatch(np)
  259.     char *np;
  260. {
  261.     register char *Np, *Bp;
  262.  
  263.     Bp = tbuf;
  264.     if (*Bp == '#')
  265.         return(0);
  266.     for (;;) {
  267.         for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  268.             continue;
  269.         if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  270.             return (1);
  271.         while (*Bp && *Bp != ':' && *Bp != '|')
  272.             Bp++;
  273.         if (*Bp == 0 || *Bp == ':')
  274.             return (0);
  275.         Bp++;
  276.     }
  277. }
  278.  
  279. /*
  280.  * Skip to the next field.  Notice that this is very dumb, not
  281.  * knowing about \: escapes or any such.  If necessary, :'s can be put
  282.  * into the termcap file in octal.
  283.  */
  284. static char *
  285. tskip(bp)
  286.     register char *bp;
  287. {
  288.  
  289.     while (*bp && *bp != ':')
  290.         bp++;
  291.     if (*bp == ':')
  292.         bp++;
  293.     return (bp);
  294. }
  295.  
  296. /*
  297.  * Return the (numeric) option id.
  298.  * Numeric options look like
  299.  *    li#80
  300.  * i.e. the option string is separated from the numeric value by
  301.  * a # character.  If the option is not found we return -1.
  302.  * Note that we handle octal numbers beginning with 0.
  303.  */
  304. tgetnum(id)
  305.     char *id;
  306. {
  307.     register int i, base;
  308.     register char *bp = tbuf;
  309.  
  310.     for (;;) {
  311.         bp = tskip(bp);
  312.         if (*bp == 0)
  313.             return (-1);
  314.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  315.             continue;
  316.         if (*bp == '@')
  317.             return(-1);
  318.         if (*bp != '#')
  319.             continue;
  320.         bp++;
  321.         base = 10;
  322.         if (*bp == '0')
  323.             base = 8;
  324.         i = 0;
  325.         while (isdigit(*bp))
  326.             i *= base, i += *bp++ - '0';
  327.         return (i);
  328.     }
  329. }
  330.  
  331. /*
  332.  * Handle a flag option.
  333.  * Flag options are given "naked", i.e. followed by a : or the end
  334.  * of the buffer.  Return 1 if we find the option, or 0 if it is
  335.  * not given.
  336.  */
  337. tgetflag(id)
  338.     char *id;
  339. {
  340.     register char *bp = tbuf;
  341.  
  342.     for (;;) {
  343.         bp = tskip(bp);
  344.         if (!*bp)
  345.             return (0);
  346.         if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
  347.             if (!*bp || *bp == ':')
  348.                 return (1);
  349.             else if (*bp == '@')
  350.                 return(0);
  351.         }
  352.     }
  353. }
  354.  
  355. /*
  356.  * Get a string valued option.
  357.  * These are given as
  358.  *    cl=^Z
  359.  * Much decoding is done on the strings, and the strings are
  360.  * placed in area, which is a ref parameter which is updated.
  361.  * No checking on area overflow.
  362.  */
  363. char *
  364. tgetstr(id, area)
  365.     char *id, **area;
  366. {
  367.     register char *bp = tbuf;
  368.  
  369.     for (;;) {
  370.         bp = tskip(bp);
  371.         if (!*bp)
  372.             return (0);
  373.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  374.             continue;
  375.         if (*bp == '@')
  376.             return(0);
  377.         if (*bp != '=')
  378.             continue;
  379.         bp++;
  380.         return (tdecode(bp, area));
  381.     }
  382. }
  383.  
  384. /*
  385.  * Tdecode does the grung work to decode the
  386.  * string capability escapes.
  387.  */
  388. static char *
  389. tdecode(str, area)
  390.     register char *str;
  391.     char **area;
  392. {
  393.     register char *cp;
  394.     register int c;
  395.     register char *dp;
  396.     int i;
  397.  
  398.     cp = *area;
  399.     while ((c = *str++) && c != ':') {
  400.         switch (c) {
  401.  
  402.         case '^':
  403.             c = *str++ & 037;
  404.             break;
  405.  
  406.         case '\\':
  407.             dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
  408.             c = *str++;
  409. nextc:
  410.             if (*dp++ == c) {
  411.                 c = *dp++;
  412.                 break;
  413.             }
  414.             dp++;
  415.             if (*dp)
  416.                 goto nextc;
  417.             if (isdigit(c)) {
  418.                 c -= '0', i = 2;
  419.                 do
  420.                     c <<= 3, c |= *str++ - '0';
  421.                 while (--i && isdigit(*str));
  422.             }
  423.             break;
  424.         }
  425.         *cp++ = c;
  426.     }
  427.     *cp++ = 0;
  428.     str = *area;
  429.     *area = cp;
  430.     return (str);
  431. }
  432.